package com.itheima.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.dfa.WordTree;
import com.alibaba.fastjson2.JSON;
import com.alibaba.nacos.common.utils.MapUtils;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.itheima.ThreadLocalUtil;
import com.itheima.dto.ArticleSaveDto;
import com.itheima.dto.MediaNewsDto;
import com.itheima.dto.PubishNewsDto;
import com.itheima.feign.MobileArticleClient;
import com.itheima.mapper.ChannelsMapper;
import com.itheima.mapper.NewsMapper;
import com.itheima.mapper.UserMapper;
import com.itheima.minIo.MinIoUtil;
import com.itheima.ocr.Tess4jClient;
import com.itheima.po.MediaChannel;
import com.itheima.po.MediaNews;
import com.itheima.po.MediaUser;
import com.itheima.service.NewsService;
import com.itheima.vo.MediaNewsVo;
import com.itheima.vo.PagingQueryVo;
import com.itheima.vo.Result;
import net.sourceforge.tess4j.TesseractException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author :wujunjie
 * createTime :2023-01-02 23:04
 * description :
 */
@Service
public class NewsServiceImpl implements NewsService {
    @Autowired
    private NewsMapper newsMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private ChannelsMapper channelsMapper;
    @Autowired
    private MobileArticleClient mobileArticleClient;
    @Autowired
    private MinIoUtil minIoUtil;
    @Autowired
    private Tess4jClient tess4jClient;
    @Override
    public PagingQueryVo<MediaNewsVo> selectNews(MediaNewsDto dto) {

        Integer size = dto.getSize();
        int start = (dto.getPage() - 1) * size;
        MPJLambdaWrapper<MediaNews> selectWrapper=new MPJLambdaWrapper<>();
        MPJLambdaWrapper<MediaNews> countWrapper=new MPJLambdaWrapper<>();

        String keyword = dto.getKeyword();
        if (!StringUtils.isEmpty(keyword)){
            selectWrapper.like(MediaNews::getTitle,keyword);
            countWrapper.like(MediaNews::getTitle,keyword);
        }
        //todo resetPage需要处理
        if (!ObjectUtils.isEmpty(dto.getChannelId())) {
            selectWrapper.eq(MediaNews::getChannelId, dto.getChannelId());
            countWrapper.eq(MediaNews::getChannelId, dto.getChannelId());
        }
        if (!ObjectUtils.isEmpty(dto.getStatus())){
            selectWrapper.eq(MediaNews::getStatus,dto.getStatus());
            countWrapper.eq(MediaNews::getStatus,dto.getStatus());
        }

        if (!ObjectUtils.isEmpty(dto.getBeginPubDate())&&!ObjectUtils.isEmpty(dto.getEndPubDate())){
            LocalTime localTime = LocalTime.of(0, 0, 0);
            LocalDateTime beginPub = LocalDateTime.of(dto.getBeginPubDate(), localTime);
            LocalDateTime endPub = LocalDateTime.of(dto.getEndPubDate(), localTime);
            selectWrapper.gt(MediaNews::getPublishTime, beginPub);
            countWrapper.gt(MediaNews::getPublishTime, beginPub);
            selectWrapper.lt(MediaNews::getPublishTime, endPub);
            countWrapper.lt(MediaNews::getPublishTime, endPub);

        }

        String last="limit " +start+","+size;
        selectWrapper.last(last);
        List<MediaNews> mediaNews = newsMapper.selectList(selectWrapper);
        if (CollectionUtils.isEmpty(mediaNews)){
            return null;
        }
        List<MediaNewsVo> mediaNewsVos = BeanUtil.copyToList(mediaNews, MediaNewsVo.class);
        PagingQueryVo<MediaNewsVo> pagingQueryVo = new PagingQueryVo<>();
        pagingQueryVo.setData(mediaNewsVos);
        pagingQueryVo.setCurrentPage(dto.getPage());
        pagingQueryVo.setSize(dto.getSize());

        Long total = newsMapper.selectCount(countWrapper);
        pagingQueryVo.setTotal(Integer.parseInt(String.valueOf(total)));
        return pagingQueryVo;
    }

    @Override
    @Transactional
    public Boolean pubishNews(PubishNewsDto dto) throws TesseractException, IOException {
        if (ObjectUtils.isEmpty(dto.getPublishTime())){
            throw new RuntimeException("发布时间不能为空");
        }
        MediaNews mediaNews = new MediaNews();
        BeanUtil.copyProperties(dto,mediaNews);
        if ("-1".equals(dto.getType())){
            SetTypeAndGetImages(mediaNews);
        }else {
            mediaNews.setType(Integer.parseInt(dto.getType()));
            mediaNews.setImages(JSON.toJSONString(dto.getImages()));
        }

        mediaNews.setUserId(Long.parseLong(ThreadLocalUtil.getId()));
        //在数据进数据库之前，对文字图片进行敏感词校验
        Boolean check=checkMediaNews(mediaNews);
        if (!check){
            mediaNews.setStatus(0);
        }
        if (mediaNews.getStatus()==0){
            mediaNews.setCreateTime(LocalDateTime.now());
            mediaNews.setId(IdUtil.getSnowflakeNextId());
            int insert = newsMapper.insert(mediaNews);
            if (insert!=1){
                throw new RuntimeException("news草稿新增失败");
            }
            throw new RuntimeException("你要发布的文章或图片中含有敏感词，已帮您存为草稿！");
        }
        if (ObjectUtils.isEmpty(mediaNews.getId())){
            MPJLambdaWrapper<MediaNews> selectWrapper = new MPJLambdaWrapper<>();
            selectWrapper.eq(MediaNews::getTitle,mediaNews.getTitle());
            MediaNews mediaNewsInDB = newsMapper.selectOne(selectWrapper);
            if (ObjectUtils.isEmpty(mediaNewsInDB)){
                mediaNews.setCreateTime(LocalDateTime.now());
                mediaNews.setSubmiteTime(LocalDateTime.now());
            }
            MediaNews mediaNewsPublish = pubishArticle(mediaNews);
            if (!ObjectUtils.isEmpty(mediaNewsPublish)){
                mediaNews.setArticleId(mediaNewsPublish.getArticleId());
            }
            mediaNews.setId(IdUtil.getSnowflakeNextId());
            int insert = newsMapper.insert(mediaNews);
            if (insert!=1){
                throw new RuntimeException("news新增失败");
            }
        }else {
            MediaNews mediaNewsInDB = newsMapper.selectById(mediaNews.getId());
            if (ObjectUtils.isEmpty(mediaNewsInDB)){
                throw new RuntimeException("需要修改的ID不存在");
            }
            mediaNews.setArticleId(mediaNewsInDB.getArticleId());
            pubishArticle(mediaNews);
            int update = newsMapper.updateById(mediaNews);
            if (update!=1){
                throw new RuntimeException("news更新失败");
            }
        }


        return true;
    }

    @Override
    public Boolean checkMediaNews(MediaNews mediaNews) throws TesseractException, IOException {
        //文字检测
        StringBuilder sb=new StringBuilder();
        sb.append(mediaNews.getLabels());
        sb.append(",").append(mediaNews.getTitle());

        List<String> images=new ArrayList<>();
        List<Map> contentMap = JSON.parseArray(mediaNews.getContent(), Map.class);

        for (Map map : contentMap) {
            if (ObjectUtils.isEmpty(map)){
                continue;
            }

            String type =String.valueOf( map.get("type"));
            if ("text".equals(type)){
               String value = String.valueOf(map.get("value"));
                sb.append(",").append(value);
            }
            if ("image".equals(type)){
                String value = String.valueOf(map.get("value"));
                images.add(value);
            }
        }
        //true为没匹配到敏感词
        Boolean  textCheck=textCheck(sb);


        //图片检测
        Boolean imageCheck=imageCheck(images);

        return textCheck&&imageCheck;
    }

    private Boolean imageCheck(List<String> images) throws IOException, TesseractException {
        //    http://39.105.134.218:9000/heimaleadnews/1111.png
        StringBuilder checkText=new StringBuilder();
        checkText.append("images:");
        for (String image : images) {
            byte[] bytes = minIoUtil.downLoadFile(image);
            ByteArrayInputStream in = new ByteArrayInputStream(bytes);    //将b作为输入流；
            BufferedImage imageBuffer = ImageIO.read(in);     //将in作为输入流，读取图片存入image中，而这里in可以为ByteArrayInputStream();
            String imageText = tess4jClient.doOCR(imageBuffer);
            checkText.append(",").append(imageText);
        }

        return textCheck(checkText);
    }

    private Boolean textCheck(StringBuilder sb) {
        int type=0;
        if (sb.toString().startsWith("images:")){
            type=1;
        }
        //todo 从数据库中读取敏感词
        WordTree wordTree = new WordTree();
        wordTree.addWord("美丽");
        List<String> list = wordTree.matchAll(sb.toString());
        //todo 需要将敏感词记录到特定的表中
        //list为空代表没匹配到敏感词
        return CollectionUtils.isEmpty(list);
    }

    @Override
    public MediaNews pubishArticle(MediaNews mediaNews) {
        if (ObjectUtils.isEmpty(mediaNews.getPublishTime())||LocalDateTime.now().isBefore(mediaNews.getPublishTime())){
            return null;
        }
        ArticleSaveDto articleSaveDto = new ArticleSaveDto();
        BeanUtil.copyProperties(mediaNews,articleSaveDto);
        articleSaveDto.setAuthorId(mediaNews.getUserId());
        MediaUser mediaUser = userMapper.selectById(mediaNews.getUserId());
        articleSaveDto.setAuthorName(mediaUser.getNickname());
        MediaChannel mediaChannel = channelsMapper.selectById(articleSaveDto.getChannelId());
        articleSaveDto.setChannelName(mediaChannel.getName());
        Integer type = mediaNews.getType();
        if (type>1){
            articleSaveDto.setLayout(2);
        }else {
            articleSaveDto.setLayout(type);
        }
        Result save = mobileArticleClient.save(articleSaveDto);
        if (save.getCode()!=200){
            throw new RuntimeException("文章添加失败");
        }
        long articleId = Long.parseLong(String.valueOf(save.getData()));
        mediaNews.setArticleId(articleId);
        return mediaNews;
    }

    @Override
    public Boolean updateById(MediaNews mediaNews) {
        MediaNews mediaNewsInDB = newsMapper.selectById(mediaNews.getId());
        if (ObjectUtils.isEmpty(mediaNewsInDB)){
            throw new RuntimeException("数据库中不存在此数据");
        }
        int update = newsMapper.updateById(mediaNews);
        return update==1;
    }

    @Override
    public Long newsDDownOrUp() {

        return null;
    }

    @Override
    public List<MediaNews> selectNewsByStatus(int status) {

        MPJLambdaWrapper<MediaNews> selectWrapper=new MPJLambdaWrapper<>();
        selectWrapper.eq(MediaNews::getStatus,status);

        return newsMapper.selectList(selectWrapper);
    }

    private void SetTypeAndGetImages(MediaNews mediaNews) {
        List<Map> content = JSON.parseArray(mediaNews.getContent(), Map.class);
        int size=0;
//        List<String> images=new ArrayList<>();
        StringBuilder images=new StringBuilder();
        for (Map map : content) {
            if (MapUtils.isEmpty(map)) {
                continue;
            }
            String type = String.valueOf(map.get("type"));
            if (StringUtils.isEmpty(type)) {
                continue;
            }
            if ("image".equals(type)) {

                size += 1;
                if (size>3){
                    continue;
                }
                String value = String.valueOf(map.get("value"));
                if (images.length() > 0) {
                    images.append(",");
                }
                images.append(value);
            }
        }

            if (size>1){
                mediaNews.setType(3);
            }else {
                mediaNews.setType(size);
            }

            mediaNews.setImages(images.toString());

    }
}
